home *** CD-ROM | disk | FTP | other *** search
/ Aminet 41 / Aminet 41 (2001)(Schatztruhe)[!][Feb 2001].iso / Aminet / gfx / fract / FlashMandel.lha / Sources / Modules / Iff.c < prev    next >
C/C++ Source or Header  |  2000-10-10  |  43KB  |  1,735 lines

  1. /******************************************************************************
  2. **
  3. **  Coded by Dino Papararo 10-October-2000
  4. **
  5. **  Based on NewIff package relased by Commodore
  6. **
  7. **  FUNCTION
  8. **
  9. **    QueryMandPic -- Examine an IFF picture.
  10. **
  11. **  SYNOPSIS
  12. **
  13. **    LONG QueryMandPic (struct ILBMInfo *,struct MandelChunk **,UBYTE *);
  14. **
  15. **  DESCRIPTION
  16. **
  17. **    Passed an initialized ILBMInfo with a not-in-use IFFHandle, a MandelChunk
  18. **
  19. **    structure and a filename, will open an ILBM, fill in ilbm->camg and
  20. **
  21. **    ilbm->bmhd, and close the ILBM.
  22. **
  23. **    This allows you to determine if the ILBM is a size and
  24. **
  25. **    type you want to deal with.
  26. **
  27. **    For succes is necessary the ID_MAND into the iff file !
  28. **
  29. **    Returns 0 for success or an IFFERR (libraries/iffparse.h).
  30. **
  31. **
  32. **  FUNCTION
  33. **
  34. **    LoadMandPic -- Load an IFF picture.
  35. **
  36. **  SYNOPSIS
  37. **
  38. **    LONG LoadMandPic (struct ILBMInfo *,UBYTE *);
  39. **
  40. **  DESCRIPTION
  41. **
  42. **    Function uses a ILBMInfo struct with record ParseInfo.iff initialized
  43. **
  44. **    with AllocIFF() function, and a pointer to a FileName.
  45. **
  46. **    It's necessary a valid Window RPort and ViewPort initialized in the passed
  47. **
  48. **    ILBM Structure for the BODY and COLORS, at end all memory will be freed.
  49. **
  50. **
  51. **  FUNCTION
  52. **
  53. **    SaveMandPic -- save a screen as IFF picture.
  54. **
  55. **  SYNOPSIS
  56. **
  57. **    LONG SaveMandPic (struct ILBMInfo *,struct Chunk *,struct Chunk *,UBYTE *);
  58. **
  59. **  DESCRIPTION
  60. **
  61. **    Function uses a ILBMInfo struct with record ParseInfo.iff initialized
  62. **
  63. **    with AllocIFF() function, two custom chunks, and a pointer to a FileName.
  64. **
  65. **    In the 1st custom chunk I put the copyright infos and in the 2nd the
  66. **
  67. **    special chunk MAND used for window limits, fractal limits, iterations
  68. **
  69. **    type...
  70. **
  71. **    Function will save the icon file too with support for NewIcons.
  72. **
  73. ******************************************************************************/
  74.  
  75. #include <proto/exec.h>
  76. #include <proto/intuition.h>
  77. #include <proto/graphics.h>
  78. #include <proto/iffparse.h>
  79.  
  80. #include <exec/types.h>
  81. #include <intuition/intuitionbase.h>
  82. #include <intuition/screens.h>
  83. #include <graphics/gfxbase.h>
  84.  
  85. #include <iffp/ilbmapp.h>
  86. #include <iffp/packer.h>
  87. #include <iffp/iffpstrings.h>
  88.  
  89. #include "compilerspecific.h"
  90.  
  91. UBYTE *omodes [2] = {"r","w"};
  92.  
  93. static BYTE *PutDump(BYTE *,int);
  94.  
  95. static BYTE *PutRun(BYTE *,int,int);
  96.  
  97. #define MaxSrcPlanes (25)
  98.  
  99. #define ID_MAND MAKE_ID('M','A','N','D')
  100.  
  101. #define NOMAND 4L
  102.  
  103. #define TOBLACK   1
  104. #define FROMBLACK 0
  105.  
  106. #define DUMP    0
  107. #define RUN 1
  108. #define MinRun 3
  109. #define MaxRun 128
  110. #define MaxDat 128
  111. #define INBUFSZ 128
  112. #define BODYBUFSZ   5004
  113. #define GetByte()       (*source++)
  114. #define PutByte(c)      { *dest++ = (c);   ++PackPutSize; }
  115. #define OutDump(nn)     dest = PutDump(dest, nn)
  116. #define OutRun(nn,cc)   dest = PutRun(dest, nn, cc)
  117. #define UGetByte()  (*source++)
  118. #define UPutByte(c) (*dest++ = (c))
  119.  
  120. IMPORT BOOL Fade (struct Window *,ULONG *,ULONG,ULONG,BOOL);
  121.  
  122. /* local function prototypes */
  123.  
  124. struct  CatCompArrayType CatCompArray [8];
  125.  
  126. LONG QueryMandPic (struct ILBMInfo *,struct MandelChunk **,UBYTE *filename);
  127.  
  128. LONG LoadMandPic (struct ILBMInfo *,UBYTE *);
  129.  
  130. LONG SaveMandPic (struct ILBMInfo *,struct Chunk *,struct Chunk *,UBYTE *);
  131.  
  132. LONG SavePalette (struct ILBMInfo *,struct Chunk *,UBYTE *);
  133.  
  134. LONG LoadPalette (struct ILBMInfo *,UBYTE *);
  135.  
  136. static LONG SAVEDS ASMCALL stdio_stream (REG (a0, struct Hook *),REG (a2,struct IFFHandle *),REG (a1,struct IFFStreamCmd *));
  137.  
  138. LONG saveilbm (struct ILBMInfo *,struct BitMap *,ULONG,WORD,WORD,WORD,WORD,APTR,UWORD,UWORD,WORD,WORD,struct Chunk *,struct Chunk *,UBYTE *);
  139.  
  140. LONG initbmhd (BitMapHeader *,struct BitMap *,WORD,WORD,WORD,WORD,WORD,WORD,WORD,ULONG);
  141.  
  142. LONG loadcmap (struct ILBMInfo *);
  143.  
  144. LONG putcmap (struct IFFHandle *,APTR,UWORD,UWORD);
  145.  
  146. LONG loadbody (struct IFFHandle *,struct BitMap *,BitMapHeader *);
  147.  
  148. LONG loadbody2 (struct IFFHandle *,struct BitMap *,BYTE *,BitMapHeader *,BYTE *,ULONG);
  149.  
  150. LONG putbody (struct IFFHandle *,struct BitMap *,BYTE *,BitMapHeader *,BYTE *,LONG);
  151.  
  152. ULONG getcamg (struct ILBMInfo *);
  153.  
  154. LONG openifile (struct ParseInfo *,UBYTE *,ULONG);
  155.  
  156. LONG parseifile (struct ParseInfo *,LONG,LONG,LONG *,LONG *,LONG *);
  157.  
  158. VOID closeifile (struct ParseInfo *);
  159.  
  160. VOID initiffasstdio (struct IFFHandle *);
  161.  
  162. LONG PutCk (struct IFFHandle *,LONG,LONG,VOID *);
  163.  
  164. LONG getcolors (struct ILBMInfo *);
  165.  
  166. LONG alloccolortable (struct ILBMInfo *);
  167.  
  168. LONG setcolors (struct ILBMInfo *,struct ViewPort *);
  169.  
  170. VOID freecolors (struct ILBMInfo *);
  171.  
  172. LONG chkcnt (LONG *);
  173.  
  174. LONG getcontext (struct IFFHandle *);
  175.  
  176. LONG contextis (struct IFFHandle *,LONG,LONG);
  177.  
  178. LONG currentchunkis (struct IFFHandle *,LONG,LONG);
  179.  
  180. UBYTE *findpropdata (struct IFFHandle *,LONG,LONG);
  181.  
  182. static BYTE *PutDump (BYTE *,int);
  183.  
  184. static BYTE *PutRun (BYTE *,int,int);
  185.  
  186. LONG PackRow (BYTE **,BYTE **,LONG);
  187.  
  188. BOOL UnPackRow (BYTE **,BYTE **,WORD,WORD);
  189.  
  190. LONG PackPutSize;
  191.  
  192. char PackBuffer [256];  /* [TBD] should be 128?  on stack?*/
  193.  
  194. struct MandelChunk { WORD LeftEdge,TopEdge,Width,Height;
  195.                      double RMin,RMax,IMin,IMax;
  196.                      double RConst,IConst;
  197.                      ULONG Iterations;
  198.                      ULONG Special;
  199.                    };
  200.  
  201. /* saveilbm
  202.  *
  203.  * Given an ILBMInfo with a currently available (not-in-use)
  204.  *   ParseInfo->iff IFFHandle, a BitMap ptr, modeid, widths/heights,
  205.  *   colortable, ncolors, bitspergun, masking, transparent color,
  206.  *   optional chunklists, and filename, will save the bitmap as an ILBM.
  207.  *
  208.  *  if bitspergun=4,  colortable is words, each with nibbles 0RGB
  209.  *  if bitspergun=8,  colortable is byte guns of RGBRGB etc. (like a CMAP)
  210.  *  if bitspergun=32, colortable is ULONG guns of RGBRGB etc.
  211.  *     Only the high eight bits of each gun will be written to CMAP.
  212.  *     Four bit guns n will be saved as nn
  213.  *
  214.  * The struct Chunk *chunklist is for chunks you wish written
  215.  * other than BMHD, CMAP, and CAMG (they will be screened out)
  216.  * because they are calculated and written separately
  217.  *
  218.  * Returns 0 for success, or an IFFERR
  219.  */
  220.  
  221. LONG saveilbm (struct ILBMInfo *ilbm,struct BitMap *bitmap,
  222.                ULONG modeid,WORD width,WORD height,WORD pagewidth,WORD pageheight,
  223.                APTR colortable,UWORD ncolors,UWORD bitspergun,
  224.                WORD masking,WORD transparentColor,
  225.                struct Chunk *chunklist1,struct Chunk *chunklist2,
  226.                UBYTE *filename)
  227. {
  228. struct IFFHandle *iff;
  229.  
  230. struct Chunk *chunk;
  231.  
  232. ULONG chunkID;
  233.  
  234. UBYTE *bodybuf;
  235.  
  236. LONG size, error;
  237.  
  238.   iff = ilbm->ParseInfo.iff;
  239.  
  240.   if (! (modeid & 0xFFFF0000)) modeid &= OLDCAMGMASK;
  241.  
  242.   if (! (bodybuf = AllocVec (BODYBUFSZ,MEMF_PUBLIC))) return (IFFERR_NOMEM);
  243.  
  244.   error = openifile (&(ilbm->ParseInfo), filename, IFFF_WRITE);
  245.  
  246.   if (! error)
  247.   {
  248.     error = PushChunk (iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);
  249.  
  250.     initbmhd (&(ilbm->Bmhd), bitmap, masking, cmpByteRun1, transparentColor, width, height, pagewidth, pageheight, modeid);
  251.  
  252.     CkErr (putbmhd (iff,&ilbm->Bmhd));
  253.  
  254.     if (colortable) CkErr (putcmap (iff,colortable,ncolors,bitspergun));
  255.  
  256.     if (ilbm->IFFPFlags & IFFPF_NOMONITOR) modeid &= (~MONITOR_ID_MASK);
  257.  
  258.     ilbm->camg = modeid;
  259.  
  260.     CkErr (putcamg (iff,&modeid));
  261.  
  262.     /* Write out chunklists 1 & 2 (if any), except for
  263.  
  264.      * any BMHD, CMAP, or CAMG (computed/written separately) */
  265.  
  266.     for (chunk = chunklist1; chunk; chunk = chunk->ch_Next)
  267.     {
  268.       chunkID = chunk->ch_ID;
  269.  
  270.       if ((chunkID != ID_BMHD) && (chunkID != ID_CMAP) && (chunkID != ID_CAMG))
  271.       {
  272.         size = chunk->ch_Size == IFFSIZE_UNKNOWN ? strlen (chunk->ch_Data) : chunk->ch_Size;
  273.  
  274.         CkErr (PutCk (iff, chunkID, size, chunk->ch_Data));
  275.       }
  276.     }
  277.  
  278.     for (chunk = chunklist2; chunk; chunk = chunk->ch_Next)
  279.     {
  280.       chunkID = chunk->ch_ID;
  281.  
  282.       if ((chunkID != ID_BMHD) && (chunkID != ID_CMAP) && (chunkID != ID_CAMG))
  283.       {
  284.         size = chunk->ch_Size == IFFSIZE_UNKNOWN ? strlen (chunk->ch_Data) : chunk->ch_Size;
  285.  
  286.         CkErr (PutCk (iff, chunkID, size, chunk->ch_Data));
  287.       }
  288.     }
  289.  
  290.     /* Write out the BODY */
  291.  
  292.     CkErr (putbody (iff, bitmap, NULL, &ilbm->Bmhd, bodybuf, BODYBUFSZ));
  293.  
  294.     CkErr (PopChunk (iff)); /* close out the FORM */
  295.  
  296.     closeifile (&(ilbm->ParseInfo));    /* and the file */
  297.   }
  298.  
  299.   FreeVec (bodybuf);
  300.  
  301.   return (error);
  302. }
  303.  
  304. /* openifile
  305.  *
  306.  * Passed a ParseInfo structure with a not-in-use IFFHandle, filename
  307.  *   and IFF open mode (IFFF_READ or IFFF_WRITE) opens file for use with
  308.  *   iffparse.library support modules.
  309.  *
  310.  * Returns 0 for success or an IFFERR (libraries/iffparse.h)
  311.  */
  312.  
  313. LONG openifile (struct ParseInfo *pi, UBYTE *filename, ULONG iffopenmode)
  314. {
  315. struct IFFHandle *iff;
  316.  
  317. LONG error = CLIENT_ERROR;
  318.  
  319.   if (! pi) return (error);
  320.  
  321.   if (! (iff = pi->iff)) return (error);
  322.  
  323.   pi->clipboard = FALSE;
  324.  
  325.   /* Set up IFFHandle for buffered stdio I/O. */
  326.  
  327.   if (! (iff->iff_Stream = (ULONG) fopen (filename,omodes [iffopenmode & 1]))) return (NOFILE);
  328.  
  329.   else initiffasstdio (iff);
  330.  
  331.   pi->filename = filename;
  332.  
  333.   error = OpenIFF (iff,iffopenmode);
  334.  
  335.   pi->opened = error ? FALSE : TRUE;    /* currently open handle */
  336.  
  337.   return (error);
  338. }
  339.  
  340. /* closeifile
  341.  *
  342.  * closes file or clipboard opened with openifile, and frees all
  343.  *   iffparse context parsed by parseifile.
  344.  *
  345.  */
  346.  
  347. void closeifile (struct ParseInfo *pi)
  348. {
  349. struct IFFHandle *iff;
  350.  
  351.   if (! pi) return;
  352.  
  353.   if (! (iff = pi->iff)) return;
  354.  
  355.   if (pi->opened) CloseIFF (iff);
  356.  
  357.   if (iff->iff_Stream)
  358.   {
  359.     if (pi->clipboard) CloseClipboard ((struct ClipboardHandle *) (iff->iff_Stream));
  360.  
  361.     else fclose ((FILE *) (iff->iff_Stream));
  362.   }
  363.  
  364.   iff->iff_Stream = NULL;
  365.  
  366.   pi->clipboard = NULL;
  367.  
  368.   pi->opened = NULL;
  369. }
  370.  
  371. /*
  372.  * File I/O hook functions which the IFF library will call.
  373.  * A return of 0 indicates success (no error).
  374.  *
  375.  * Iffparse.library calls this code via struct Hook and Hook.asm
  376.  */
  377. static LONG SAVEDS ASMCALL stdio_stream (REG (a0,struct Hook *hook),REG (a2,struct IFFHandle *iff),REG (a1,struct IFFStreamCmd *actionpkt))
  378. {
  379. register FILE *stream;
  380. register LONG nbytes;
  381. register LONG actual;
  382. register UBYTE *buf;
  383. LONG len;
  384.  
  385.   stream = (FILE *) iff->iff_Stream;
  386.  
  387.   if (! stream) return (1L);
  388.  
  389.   nbytes = actionpkt->sc_NBytes;
  390.  
  391.   buf = (UBYTE *) actionpkt->sc_Buf;
  392.  
  393.   switch (actionpkt->sc_Command)
  394.   {
  395.     case IFFSCC_READ: do
  396.                       {  actual = (nbytes > 32767 ? 32767 : nbytes);
  397.  
  398.                          if ((len = fread (buf, 1, (size_t) actual, stream)) != actual) break;
  399.  
  400.                          nbytes -= actual;
  401.  
  402.                          buf += actual;
  403.  
  404.                       } while (nbytes > NULL);
  405.  
  406.                       return (nbytes ? IFFERR_READ : NULL);
  407.  
  408.     case IFFSCC_WRITE: do
  409.                        {  actual = (nbytes > 32767 ? 32767 : nbytes);
  410.  
  411.                           if ((len = fwrite (buf, 1, (size_t) actual, stream)) != actual) break;
  412.  
  413.                           nbytes -= actual;
  414.  
  415.                           buf += actual;
  416.  
  417.                        } while (nbytes > NULL);
  418.  
  419.                        return (nbytes ? IFFERR_WRITE : NULL);
  420.  
  421.     case IFFSCC_SEEK:  return ((fseek (stream, nbytes, 1) == -1) ? IFFERR_SEEK : NULL);
  422.  
  423.     default:           return (NULL);  /*  No _INIT or _CLEANUP required.  */
  424.   }
  425. }
  426.  
  427. /* initiffasstdio (ie. init iff as stdio)
  428.  *
  429.  * sets up hook callback for the file stream handler above
  430.  */
  431.  
  432. void initiffasstdio (struct IFFHandle *iff)
  433. {
  434. static struct Hook stdiohook = {{NULL},(ULONG (*)()) stdio_stream,NULL,NULL};
  435.  
  436. /*
  437.  * Initialize the IFF structure to point to the buffered I/O
  438.  * routines.  Unbuffered I/O is terribly slow.
  439.  */
  440.  
  441.   InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
  442. }
  443.  
  444. /* PutCk
  445.  * Writes one chunk of data to an iffhandle
  446.  */
  447.  
  448. LONG PutCk (struct IFFHandle *iff,long id,long size,void *data)
  449. {
  450. LONG error,wlen;
  451.  
  452.   if (! (error = PushChunk (iff,0,id,size)))
  453.   {
  454.      /* Write the actual data */
  455.  
  456.      if ((wlen = WriteChunkBytes (iff,data,size)) != size) error = IFFERR_WRITE;
  457.  
  458.      else error = PopChunk (iff);
  459.   }
  460.  
  461.   return (error);
  462. }
  463.  
  464. /*---------- initbmhd -------------------------------------------------*/
  465.  
  466. LONG initbmhd (BitMapHeader *bmhd, struct BitMap *bitmap,
  467.                WORD masking, WORD compression, WORD transparentColor,
  468.                WORD width, WORD height, WORD pageWidth, WORD pageHeight,
  469.                ULONG modeid)
  470. {
  471.   struct DisplayInfo DI;
  472.  
  473.   if ((! bmhd) || (! bitmap) || (! width) || (! height)) return (CLIENT_ERROR);
  474.  
  475.   bmhd->w = width;
  476.  
  477.   bmhd->h = height;
  478.  
  479.   bmhd->x = bmhd->y = 0;    /* Default position is (0,0).*/
  480.  
  481.   bmhd->nPlanes = bitmap->Depth;
  482.  
  483.   bmhd->masking = masking;
  484.  
  485.   bmhd->compression = compression;
  486.  
  487.   bmhd->flags = BMHDF_CMAPOK;   /* we will store 8 significant bits */
  488.  
  489.   bmhd->transparentColor = transparentColor;
  490.  
  491.   bmhd->pageWidth = pageWidth;
  492.  
  493.   bmhd->pageHeight = pageHeight;
  494.  
  495.   bmhd->xAspect = 0;    /* So we can tell when we've got it */
  496.  
  497.   if (GetDisplayInfoData (NULL, (UBYTE *) &DI, sizeof (struct DisplayInfo), DTAG_DISP, modeid))
  498.   {
  499.      bmhd->xAspect = DI.Resolution.x;
  500.  
  501.      bmhd->yAspect = DI.Resolution.y;
  502.   }
  503.  
  504.     /* If running under 1.3 or GetDisplayInfoData failed, use old method
  505.      * of guessing aspect ratio */
  506.  
  507.   if (! bmhd->xAspect)
  508.   {
  509.     bmhd->xAspect =  44;
  510.  
  511.     bmhd->yAspect = ((struct GfxBase *) GfxBase)->DisplayFlags & PAL ? 44 : 52;
  512.  
  513.     if (modeid & HIRES) bmhd->xAspect = bmhd->xAspect >> 1;
  514.  
  515.     if (modeid & LACE)  bmhd->yAspect = bmhd->yAspect >> 1;
  516.   }
  517.  
  518.   return (IFF_OKAY);
  519. }
  520.  
  521. /*---------- putcmap ---------------------------------------------------*/
  522. /*  This function will accept a table of color values in one of the
  523.  *  following forms:
  524.  *  if bitspergun=4,  colortable is words, each with nibbles 0RGB
  525.  *  if bitspergun=8,  colortable is bytes of RGBRGB etc. (like a CMAP)
  526.  *  if bitspergun=32, colortable is ULONGS of RGBRGB etc.
  527.  *  (only the high eight bits of each gun will be written to CMAP)
  528.  */
  529.  
  530. LONG putcmap (struct IFFHandle *iff,APTR colortable,UWORD ncolors,UWORD bitspergun)
  531. {
  532. LONG error, offs;
  533.  
  534. UWORD  *tabw;
  535.  
  536. UBYTE *tab8;
  537.  
  538. ColorRegister cmapReg;
  539.  
  540.   if ((! iff) || (! colortable)) return (CLIENT_ERROR);
  541.  
  542.   /* size of CMAP is 3 bytes * ncolors */
  543.  
  544.   if (error = PushChunk (iff,NULL,ID_CMAP,(LONG) (ncolors * sizeofColorRegister))) return (error);
  545.  
  546.   if (bitspergun == 4)
  547.   {
  548.     /* Store each 4-bit value n as nn */
  549.  
  550.     tabw = (UWORD *) colortable;
  551.  
  552.     for (; ncolors; --ncolors)
  553.     {
  554.       cmapReg.red    = ( *tabw >> 4 ) & 0xf0;
  555.  
  556.       cmapReg.red   |= (cmapReg.red >> 4);
  557.  
  558.       cmapReg.green  = ( *tabw      ) & 0xf0;
  559.  
  560.       cmapReg.green |= (cmapReg.green >> 4);
  561.  
  562.       cmapReg.blue   = ( *tabw << 4 ) & 0xf0;
  563.  
  564.       cmapReg.blue  |= (cmapReg.blue >> 4);
  565.  
  566.       if ((WriteChunkBytes (iff,(BYTE *) &cmapReg,sizeofColorRegister)) != sizeofColorRegister) return (IFFERR_WRITE);
  567.  
  568.       ++tabw;
  569.     }
  570.   }
  571.  
  572.   else
  573.  
  574.     if ((bitspergun == 8) || (bitspergun == 32))
  575.     {
  576.       tab8 = (UBYTE *) colortable;
  577.  
  578.       offs = (bitspergun == 8) ? 1 : 4;
  579.  
  580.       for ( ;  ncolors;  --ncolors )
  581.       {
  582.         cmapReg.red   = *tab8;
  583.  
  584.         tab8 += offs;
  585.  
  586.         cmapReg.green = *tab8;
  587.  
  588.         tab8 += offs;
  589.  
  590.         cmapReg.blue  = *tab8;
  591.  
  592.         tab8 += offs;
  593.  
  594.         if ((WriteChunkBytes (iff,(BYTE *) &cmapReg,sizeofColorRegister)) != sizeofColorRegister) return (IFFERR_WRITE);
  595.       }
  596.     }
  597.  
  598.   error = PopChunk (iff);
  599.  
  600.   return (error);
  601. }
  602.  
  603. /*---------- putbody ---------------------------------------------------*/
  604. /* NOTE: This implementation could be a LOT faster if it used more of the
  605.  * supplied buffer. It would make far fewer calls to IFFWriteBytes (and
  606.  * therefore to DOS Write).
  607.  *
  608.  * Incorporates modification by Jesper Steen Moller to accept source
  609.  * rows wider than dest rows, with one modulo variable for source bitplane
  610.  * rows and one for the ILBM bitmap rows.
  611.  */
  612.  
  613. LONG putbody (struct IFFHandle *iff, struct BitMap *bitmap, BYTE *mask,BitMapHeader *bmhd, BYTE *buffer, LONG bufsize)
  614. {
  615. LONG error;
  616.  
  617. LONG rowBytes = bitmap->BytesPerRow;   /* for source modulo only */
  618.  
  619. LONG FileRowBytes = RowBytes (bmhd->w); /* width to write in bytes */
  620.  
  621. int dstDepth = bmhd->nPlanes;
  622.  
  623. UBYTE compression = bmhd->compression;
  624.  
  625. int planeCnt;                          /* number of bit planes including mask */
  626.  
  627. register int iPlane, iRow;
  628.  
  629. register LONG packedRowBytes;
  630.  
  631. BYTE *buf;
  632.  
  633. BYTE *planes [MAXSAVEDEPTH + 1];        /* array of ptrs to planes & mask */
  634.  
  635.   if ( bufsize < MaxPackedSize (FileRowBytes) ||  /* Must buffer a comprsd row*/
  636.  
  637.        compression > cmpByteRun1              ||  /* bad arg */
  638.  
  639.        bitmap->Rows != bmhd->h                ||  /* inconsistent */
  640.  
  641.        rowBytes < FileRowBytes                ||  /* inconsistent*/
  642.  
  643.        bitmap->Depth < dstDepth               ||  /* inconsistent */
  644.  
  645.        dstDepth > MAXSAVEDEPTH )                  /* too many for this routine*/
  646.  
  647.     return (CLIENT_ERROR);
  648.  
  649.   planeCnt = dstDepth + (mask == NULL ? 0 : 1);
  650.  
  651.   /* Copy the ptrs to bit & mask planes into local array "planes" */
  652.  
  653.   for (iPlane = 0; iPlane < dstDepth; iPlane++) planes [iPlane] = (BYTE *) bitmap->Planes [iPlane];
  654.  
  655.   if (mask != NULL) planes [dstDepth] = mask;
  656.  
  657.   /* Write out a BODY chunk header */
  658.  
  659.   if (error = PushChunk (iff, NULL, ID_BODY, IFFSIZE_UNKNOWN)) return (error);
  660.  
  661.   /* Write out the BODY contents */
  662.  
  663.   for (iRow = bmhd->h; iRow > 0; iRow--)
  664.   {
  665.     for (iPlane = 0; iPlane < planeCnt; iPlane++)
  666.     {
  667.       /* Write next row.*/
  668.  
  669.       if (compression == cmpNone)
  670.       {
  671.         if (WriteChunkBytes (iff,planes [iPlane],FileRowBytes) != FileRowBytes) error = IFFERR_WRITE;
  672.  
  673.         planes [iPlane] += rowBytes; /* Possibly skipping unused bytes */
  674.       }
  675.  
  676.       else                     /* Compress and write next row.*/
  677.       {
  678.         buf = buffer;
  679.  
  680.         packedRowBytes = PackRow (&planes [iPlane], &buf, FileRowBytes);
  681.  
  682.         /* Note that packrow incremented planes already by FileRowBytes */
  683.  
  684.         planes [iPlane] += rowBytes-FileRowBytes; /* Possibly skipping unused bytes */
  685.  
  686.         if (WriteChunkBytes (iff,buffer,packedRowBytes) != packedRowBytes) error = IFFERR_WRITE;
  687.       }
  688.  
  689.       if (error) return (error);
  690.     }
  691.   }
  692.  
  693.   /* Finish the chunk */
  694.  
  695.   error = PopChunk (iff);
  696.  
  697.   return (error);
  698. }
  699.  
  700. LONG loadcmap (struct ILBMInfo *ilbm)
  701. {
  702. struct StoredProperty *sp;
  703.  
  704. struct IFFHandle *iff;
  705.  
  706. BOOL AllShifted;
  707.  
  708. UBYTE *rgb, rb, gb, bb;
  709.  
  710. LONG k;
  711.  
  712. ULONG ncolors, gun, ncheck, nc, r, g, b;
  713.  
  714.   if (! (iff = ilbm->ParseInfo.iff)) return (CLIENT_ERROR);
  715.  
  716.   if (! (ilbm->colortable)) return (1L);
  717.  
  718.   if (! (sp = FindProp (iff, ID_ILBM, ID_CMAP))) return (1L);
  719.  
  720.   rgb = sp->sp_Data;
  721.  
  722.   /* file has this many colors */
  723.  
  724.   nc = sp->sp_Size / sizeofColorRegister;
  725.  
  726.   ncolors = nc;
  727.  
  728.   /* if ILBMInfo can't hold that many, we'll load less */
  729.  
  730.   if (ilbm->ncolors < ncolors) ncolors = ilbm->ncolors;
  731.  
  732.   /* set to how many we are loading */
  733.  
  734.   ilbm->ncolors = ncolors;
  735.  
  736.   /* how many colors to check for shifted nibbles (i.e. used colors) */
  737.  
  738.   ncheck = 1L << ilbm->Bmhd.nPlanes;
  739.  
  740.   if (ncheck > ncolors) ncheck = ncolors;
  741.  
  742.   if ((! (ilbm->IFFPFlags & IFFPF_NOCOLOR32)) && (ilbm->colorrecord))
  743.   {
  744.     ilbm->colorrecord [0] = ncolors << 16L;
  745.  
  746.     /* Assign to 32-bit table, examine for all-shifted nibbles at same time */
  747.  
  748.     AllShifted = TRUE;
  749.  
  750.     k = 0;
  751.  
  752.     while (ncheck--)
  753.     {
  754.       ilbm->colortable32 [k].r = rb = *rgb++;
  755.  
  756.       ilbm->colortable32 [k].g = gb = *rgb++;
  757.  
  758.       ilbm->colortable32 [k].b = bb = *rgb++;
  759.  
  760.       if (((rb & 0x0F) || (gb & 0x0F) || (bb & 0x0F))) AllShifted = FALSE;
  761.  
  762.       k++;
  763.     }
  764.  
  765.     /* If no file/user indication that this is an 8-bit significant CMAP... */
  766.  
  767.     if ((! (ilbm->IFFPFlags & IFFPF_CMAPOK)) && (! (ilbm->Bmhd.flags & BMHDF_CMAPOK)))
  768.     {
  769.       /* If all nibbles appear shifted (4 bit), duplicate the nibbles */
  770.  
  771.       if (AllShifted)
  772.       {
  773.         for (k = 0; k < nc; k++)
  774.         {
  775.           ilbm->colortable32 [k].r |= (ilbm->colortable32 [k].r >> 4);
  776.  
  777.           ilbm->colortable32 [k].g |= (ilbm->colortable32 [k].g >> 4);
  778.  
  779.           ilbm->colortable32 [k].b |= (ilbm->colortable32 [k].b >> 4);
  780.         }
  781.       }
  782.     }
  783.  
  784.     /* Now scale to 32 bits */
  785.  
  786.     for (k = 0; k < nc; k++)
  787.     {
  788.       gun = ilbm->colortable32 [k].r;
  789.  
  790.       ilbm->colortable32 [k].r |= ((gun << 24) | (gun << 16) | (gun << 8));
  791.  
  792.       gun = ilbm->colortable32 [k].g;
  793.  
  794.       ilbm->colortable32 [k].g |= ((gun << 24) | (gun << 16) | (gun << 8));
  795.  
  796.       gun = ilbm->colortable32 [k].b;
  797.  
  798.       ilbm->colortable32 [k].b |= ((gun << 24) | (gun << 16) | (gun << 8));
  799.     }
  800.   }
  801.  
  802.   /* always make old-style table */
  803.  
  804.   rgb = sp->sp_Data;
  805.  
  806.   ncolors = nc;
  807.  
  808.   k = 0;
  809.  
  810.   while (ncolors--)
  811.   {
  812.     r = (*rgb++ & 0xF0) << 4;
  813.  
  814.     g = *rgb++ & 0xF0;
  815.  
  816.     b = *rgb++ >> 4;
  817.  
  818.     ilbm->colortable [k] = r | g | b;
  819.  
  820.     k++;
  821.   }
  822.  
  823.   return (NULL);
  824. }
  825.  
  826. LONG getcolors (struct ILBMInfo *ilbm)
  827. {
  828. struct IFFHandle *iff;
  829.  
  830. LONG error = CLIENT_ERROR;
  831.  
  832.   if (! (iff = ilbm->ParseInfo.iff)) return (error);
  833.  
  834.   if (! (error = alloccolortable (ilbm))) error = loadcmap (ilbm);
  835.  
  836.   if (error) freecolors (ilbm);
  837.  
  838.   return (error);
  839. }
  840.  
  841. /* alloccolortable - allocates ilbm->colortable and sets ilbm->ncolors
  842.  *  to the number of colors we have room for in the table.
  843.  *
  844.  * V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will also
  845.  *  allocate and build a 32-bit per gun colortable (ilbm->colortable32)
  846.  *  and ilbm->colorrecord for LoadRGB32()
  847.  */
  848.  
  849. LONG alloccolortable (struct ILBMInfo *ilbm)
  850. {
  851. struct IFFHandle *iff;
  852.  
  853. struct StoredProperty *sp;
  854.  
  855. LONG error = NULL;
  856.  
  857. ULONG ctabsize;
  858.  
  859. UWORD ncolors;
  860.  
  861.   if (! (iff = ilbm->ParseInfo.iff)) return (CLIENT_ERROR);
  862.  
  863.   if (sp = FindProp (iff,ID_ILBM,ID_CMAP))
  864.   {
  865.      /*
  866.       * Compute the size table we need
  867.       */
  868.  
  869.      ncolors = sp->sp_Size / 3;     /* how many in CMAP */
  870.  
  871.      ncolors = MAX (ncolors,16);    /* alloc at least 16 */
  872.  
  873.      ctabsize = ncolors * sizeof (Color4);
  874.  
  875.      if (ilbm->colortable = (Color4 *) AllocVec (ctabsize,MEMF_PUBLIC | MEMF_CLEAR))
  876.      {
  877.     ilbm->ncolors = ncolors;
  878.  
  879.     ilbm->ctabsize = ctabsize;
  880.  
  881.         if ((! (ilbm->IFFPFlags & IFFPF_NOCOLOR32)))
  882.     {
  883.            ctabsize = (ncolors * sizeof (Color32)) + (2 * sizeof (LONG));
  884.  
  885.        if (ilbm->colorrecord = (WORD *) AllocVec (ctabsize,MEMF_PUBLIC | MEMF_CLEAR))
  886.            {
  887.           ilbm->crecsize = ctabsize;
  888.  
  889.           ilbm->colortable32 = (Color32 *) (&ilbm->colorrecord [1L]);
  890.  
  891.           ilbm->colorrecord [0L] = ncolors << 16L;   /* For LoadRGB32 */
  892.  
  893.               ilbm->colorrecord [ncolors * sizeof (Color32) + 1L] = NULL;
  894.            }
  895.  
  896.            else error = IFFERR_NOMEM;
  897.         }
  898.      }
  899.  
  900.      else error = IFFERR_NOMEM;
  901.   }
  902.  
  903.   if (error) freecolors (ilbm);
  904.  
  905.   return (error);
  906. }
  907.  
  908. VOID freecolors (struct ILBMInfo *ilbm)
  909. {
  910.    if (ilbm->colortable) FreeVec (ilbm->colortable);
  911.  
  912.    ilbm->colortable = NULL;
  913.  
  914.    ilbm->ctabsize = 0;
  915.  
  916.    if (ilbm->colorrecord) FreeVec (ilbm->colorrecord);
  917.  
  918.    ilbm->colorrecord  = NULL;
  919.  
  920.    ilbm->colortable32 = NULL;
  921.  
  922.    ilbm->crecsize = 0;
  923. }
  924.  
  925. LONG currentchunkis (struct IFFHandle *iff,LONG type,LONG id)
  926. {
  927. register struct ContextNode *cn;
  928.  
  929. LONG result = 0;
  930.  
  931.   if (cn = CurrentChunk (iff))
  932.  
  933.     if ((cn->cn_Type == type) && (cn->cn_ID == id)) result = 1;
  934.  
  935.   return (result);
  936. }
  937.  
  938. /*---------- loadbody ---------------------------------------------------*/
  939.  
  940. LONG loadbody (struct IFFHandle *iff,struct BitMap *bitmap,BitMapHeader *bmhd)
  941. {
  942. BYTE *buffer;
  943.  
  944. ULONG bufsize;
  945.  
  946. LONG error = 1L;
  947.  
  948.   if (! (currentchunkis (iff,ID_ILBM,ID_BODY))) return (IFF_OKAY);
  949.  
  950.   if ((bitmap) && (bmhd))
  951.   {
  952.      bufsize = MaxPackedSize (RowBytes (bmhd->w)) << 4L;
  953.  
  954.      if (! (buffer = AllocVec (bufsize,0L))) return (IFFERR_NOMEM);
  955.  
  956.      error = loadbody2 (iff,bitmap,NULL,bmhd,buffer,bufsize);
  957.  
  958.      FreeVec (buffer);
  959.   }
  960.  
  961.   return (error);
  962. }
  963.  
  964. LONG loadbody2 (struct IFFHandle *iff,struct BitMap *bitmap,BYTE *mask,BitMapHeader *bmhd,BYTE *buffer,ULONG bufsize)
  965. {
  966. UBYTE srcPlaneCnt = bmhd->nPlanes;   /* Haven't counted for mask plane yet*/
  967.  
  968. WORD srcRowBytes = RowBytes (bmhd->w);
  969.  
  970. WORD destRowBytes = bitmap->BytesPerRow;   /* used as a modulo only */
  971.  
  972. LONG bufRowBytes = MaxPackedSize (srcRowBytes);
  973.  
  974. WORD nRows = bmhd->h;
  975.  
  976. WORD destWidthBytes;            /* used for width check */
  977.  
  978. WORD compression = bmhd->compression;
  979.  
  980. register WORD iPlane, iRow, nEmpty;
  981.  
  982. register WORD nFilled;
  983.  
  984. BYTE *buf, *nullDest, *nullBuf, **pDest;
  985.  
  986. BYTE *planes [MaxSrcPlanes]; /* array of ptrs to planes & mask */
  987.  
  988. struct ContextNode *cn;
  989.  
  990.    cn = CurrentChunk (iff);
  991.  
  992.    if (compression > cmpByteRun1) return (CLIENT_ERROR);
  993.  
  994.    /* If >=V39, this may be an interleaved bitmap with a BytesPerRow
  995.     * which is truly just a modulo and actually includes ALL planes.
  996.     * So instead, for bounds checking, we use the pixel width of
  997.     * the BitMap rounded up to nearest WORD, since saved ILBMs
  998.     * are always saved as their width rounded up to nearest WORD.
  999.     */
  1000.  
  1001.    destWidthBytes = RowBytes (GetBitMapAttr (bitmap,BMA_WIDTH));
  1002.  
  1003.    /* Complain if client asked for a conversion GetBODY doesn't handle.*/
  1004.  
  1005.    if (srcRowBytes > destWidthBytes || bufsize < (bufRowBytes * 2) || srcPlaneCnt > MaxSrcPlanes) return (CLIENT_ERROR);
  1006.  
  1007.    if (nRows > bitmap->Rows) nRows = bitmap->Rows;
  1008.  
  1009.    /* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
  1010.  
  1011.    for (iPlane = 0; iPlane < bitmap->Depth; iPlane++) planes [iPlane] = (BYTE *) bitmap->Planes [iPlane];
  1012.  
  1013.    for ( ; iPlane < MaxSrcPlanes; iPlane++) planes [iPlane] = NULL;
  1014.  
  1015.    /* Copy any mask plane ptr into corresponding "planes" slot.*/
  1016.  
  1017.    if (bmhd->masking == mskHasMask)
  1018.    {
  1019.       if (mask) planes [srcPlaneCnt] = mask;  /* If there are more srcPlanes than
  1020.  
  1021.                                                * dstPlanes, there will be NULL plane-pointers before this. */
  1022.  
  1023.       else  planes [srcPlaneCnt] = NULL;  /* In case more dstPlanes than src. */
  1024.  
  1025.       srcPlaneCnt += 1;  /* Include mask plane in count.*/
  1026.    }
  1027.  
  1028.    /* Setup a sink for dummy destination of rows from unwanted planes.*/
  1029.  
  1030.    nullDest = buffer;
  1031.  
  1032.    buffer  += srcRowBytes;
  1033.  
  1034.    bufsize -= srcRowBytes;
  1035.  
  1036.    /* Read the BODY contents into client's bitmap.
  1037.     * De-interleave planes and decompress rows.
  1038.     * MODIFIES: Last iteration modifies bufsize.*/
  1039.  
  1040.    buf = buffer + bufsize;  /* Buffer is currently empty.*/
  1041.  
  1042.    for (iRow = nRows; iRow > 0; iRow--)
  1043.    {
  1044.        for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)
  1045.        {
  1046.         pDest = &planes [iPlane];
  1047.  
  1048.             /* Establish a sink for any unwanted plane.*/
  1049.  
  1050.             if (*pDest == NULL)
  1051.             {
  1052.             nullBuf = nullDest;
  1053.  
  1054.                 pDest   = &nullBuf;
  1055.             }
  1056.  
  1057.             /* Read in at least enough bytes to uncompress next row.*/
  1058.  
  1059.             nEmpty  = buf - buffer;   /* size of empty part of buffer.*/
  1060.  
  1061.             nFilled = bufsize - nEmpty;   /* this part has data.*/
  1062.  
  1063.         if (nFilled < bufRowBytes)
  1064.             {
  1065.             /* Need to read more.*/
  1066.             /* Move the existing data to the front of the buffer.*/
  1067.             /* Now covers range buffer[0]..buffer[nFilled-1].*/
  1068.  
  1069.                 CopyMem (buf,buffer,nFilled);  /* Could be moving 0 bytes.*/
  1070.  
  1071.                 if (nEmpty > ChunkMoreBytes (cn))
  1072.         {
  1073.                     /* There aren't enough bytes left to fill the buffer.*/
  1074.  
  1075.                     nEmpty = ChunkMoreBytes (cn);
  1076.  
  1077.                     bufsize = nFilled + nEmpty;  /* heh-heh */
  1078.                 }
  1079.  
  1080.             /* Append new data to the existing data.*/
  1081.  
  1082.                 if (ReadChunkBytes (iff,&buffer [nFilled],(LONG) nEmpty) < nEmpty) return (CLIENT_ERROR);
  1083.  
  1084.                 buf = buffer;
  1085.  
  1086.             nFilled = bufsize;
  1087.             }
  1088.  
  1089.         /* Copy uncompressed row to destination plane.*/
  1090.  
  1091.             if (compression == cmpNone)
  1092.             {
  1093.                 if (nFilled < srcRowBytes)  return (IFFERR_MANGLED);
  1094.  
  1095.             CopyMem (buf,*pDest,srcRowBytes);
  1096.  
  1097.             buf    += srcRowBytes;
  1098.  
  1099.                 *pDest += destRowBytes;
  1100.             }
  1101.  
  1102.         else
  1103.             {
  1104.             /* Decompress row to destination plane.*/
  1105.  
  1106.                 if (UnPackRow (&buf,pDest,nFilled,srcRowBytes)) return (IFFERR_MANGLED);
  1107.  
  1108.                            /*  pSource, pDest, srcBytes, dstBytes  */
  1109.  
  1110.             else *pDest += (destRowBytes - srcRowBytes);
  1111.  
  1112.             }
  1113.     }
  1114.    }
  1115.  
  1116.    return (IFF_OKAY);
  1117. }
  1118.  
  1119. ULONG getcamg (struct ILBMInfo *ilbm)
  1120. {
  1121. struct IFFHandle *iff;
  1122.  
  1123. struct StoredProperty *sp;
  1124.  
  1125. UWORD wide,high,deep;
  1126.  
  1127. ULONG modeid = NULL;
  1128.  
  1129.   if (! (iff = ilbm->ParseInfo.iff)) return (NULL);
  1130.  
  1131.   wide = ilbm->Bmhd.pageWidth;
  1132.  
  1133.   high = ilbm->Bmhd.pageHeight;
  1134.  
  1135.   deep = ilbm->Bmhd.nPlanes;
  1136.  
  1137.   /* Grab CAMG's idea of the viewmodes */
  1138.  
  1139.   if (sp = FindProp (iff, ID_ILBM, ID_CAMG))
  1140.   {
  1141.      modeid = (* (ULONG *) sp->sp_Data);
  1142.  
  1143.      /* knock bad bits out of old-style 16-bit viewmode CAMGs */
  1144.  
  1145.      if ((! (modeid & MONITOR_ID_MASK)) || ((modeid & EXTENDED_MODE) && (! (modeid & 0xFFFF0000)))) modeid &= (~(EXTENDED_MODE | SPRITES | GENLOCK_AUDIO | GENLOCK_VIDEO | VP_HIDE));
  1146.  
  1147.      /* check for bogus CAMG like DPaintII brushes
  1148.       * with junk in upper word and extended bit
  1149.       * not set in lower word.
  1150.       */
  1151.  
  1152.      if ((modeid & 0xFFFF0000) && (! (modeid & 0x00001000))) sp = NULL;
  1153.   }
  1154.  
  1155.   if (! sp)
  1156.   {
  1157.      /*
  1158.       * No CAMG (or bad CAMG) present; use computed modes.
  1159.       */
  1160.  
  1161.      modeid = NULL;     /* added in 39.6 */
  1162.  
  1163.      if (wide >= 640) modeid = HIRES;
  1164.  
  1165.      if (high >= 400) modeid |= LACE;
  1166.  
  1167.      if (deep == 6)
  1168.      {
  1169.         modeid |= ilbm->EHB ? EXTRA_HALFBRITE : HAM;
  1170.      }
  1171.   }
  1172.  
  1173.   if (ilbm->IFFPFlags & IFFPF_NOMONITOR) modeid &= (~MONITOR_ID_MASK);
  1174.  
  1175.   return (modeid);
  1176. }
  1177.  
  1178. LONG chkcnt (LONG *TaggedArray)
  1179. {
  1180. LONG k = 0;
  1181.  
  1182.   while (TaggedArray [k] != TAG_END) k++;
  1183.  
  1184.   return (k >> 1);
  1185. }
  1186.  
  1187. LONG getcontext (struct IFFHandle *iff)
  1188. {
  1189. LONG error;
  1190.  
  1191.   /* Based on our parse initialization, ParseIFF() will return on a stop chunk
  1192.    * (error = 0) or end of context for an ILBM FORM (error = IFFERR_EOC) or end of
  1193.    * file (error = IFFERR_EOF)
  1194.    */
  1195.  
  1196.   return (error = ParseIFF (iff,IFFPARSE_SCAN));
  1197. }
  1198.  
  1199. LONG parseifile (struct ParseInfo *pi,LONG groupid,LONG grouptype,LONG *propchks,LONG *collectchks,LONG *stopchks)
  1200. {
  1201. struct IFFHandle *iff;
  1202.  
  1203. register struct ContextNode *cn;
  1204.  
  1205. LONG error;
  1206.  
  1207.   if (! (iff = pi->iff)) return (CLIENT_ERROR);
  1208.  
  1209.   if (! iff->iff_Stream) return (IFFERR_READ);
  1210.  
  1211.   pi->hunt = FALSE;
  1212.  
  1213.   /* Declare property, collection and stop chunks.*/
  1214.  
  1215.   if (propchks)
  1216.  
  1217.       if (error = PropChunks (iff, propchks, chkcnt (propchks))) return (error);
  1218.  
  1219.   if (collectchks)
  1220.  
  1221.           if (error = CollectionChunks (iff, collectchks, chkcnt (collectchks))) return (error);
  1222.  
  1223.   if (stopchks)
  1224.  
  1225.           if (error = StopChunks (iff, stopchks, chkcnt (stopchks))) return (error);
  1226.  
  1227.     /* We want to stop at the end of an ILBM context. */
  1228.  
  1229.   if (grouptype)
  1230.  
  1231.       if (error = StopOnExit (iff, grouptype, groupid)) return (error);
  1232.  
  1233.     /* Take first parse step to enter main chunk. */
  1234.  
  1235.   if (error = ParseIFF (iff,IFFPARSE_STEP)) return (error);
  1236.  
  1237.     /* Test the chunk info to see if simple form of type we want (ILBM).*/
  1238.  
  1239.   if (! (cn = CurrentChunk (iff))) return (NOFILE); /* This really should never happen.  If it does, it means our parser is broken. */
  1240.  
  1241.   if (cn->cn_ID != groupid || cn->cn_Type != grouptype) pi->hunt = TRUE; /* Warning - this is a complex file */
  1242.  
  1243.   if (! error) error = getcontext (iff);
  1244.  
  1245.   return (error);
  1246. }
  1247.  
  1248. LONG contextis (struct IFFHandle *iff,LONG type,LONG id)
  1249. {
  1250. register struct ContextNode *cn;
  1251.  
  1252. LONG result = NULL;
  1253.  
  1254.   if (cn = (CurrentChunk (iff)))
  1255.   {
  1256.     if (cn = (ParentChunk (cn)))
  1257.     {
  1258.       if ((cn->cn_Type == type) && (cn->cn_ID == id)) result = 1L;
  1259.     }
  1260.   }
  1261.  
  1262.   return (result);
  1263. }
  1264.  
  1265. UBYTE *findpropdata (struct IFFHandle *iff,LONG type,LONG id)
  1266. {
  1267. register struct StoredProperty *sp;
  1268.  
  1269.   if (sp = FindProp (iff,type,id)) return (sp->sp_Data);
  1270.  
  1271.   return (0);
  1272. }
  1273.  
  1274. LONG setcolors (struct ILBMInfo *ilbm,struct ViewPort *vp)
  1275. {
  1276. LONG ncolors;
  1277.  
  1278.   if (! vp) return (CLIENT_ERROR);
  1279.  
  1280.   ncolors = MIN (ilbm->ncolors,vp->ColorMap->Count);
  1281.  
  1282.   if ((! (ilbm->IFFPFlags & IFFPF_NOCOLOR32)) && (ilbm->colorrecord))
  1283.  
  1284.      Fade (ilbm->win,(ULONG *) ilbm->colorrecord,25L,1L,FROMBLACK);
  1285.  
  1286.   else
  1287.  
  1288.      if (ilbm->colortable) LoadRGB4 (vp,(UWORD *) ilbm->colortable,ncolors);
  1289.  
  1290.   return (NULL);
  1291. }
  1292.  
  1293. /**********  ByteRun1 ***************************************************/
  1294.  
  1295. static BYTE *PutDump (BYTE *dest, int nn)
  1296. {
  1297.   LONG i;
  1298.  
  1299.   PutByte (nn-1);
  1300.  
  1301.   for (i = 0;  i < nn;  i++) PutByte (PackBuffer [i]);
  1302.  
  1303.   return (dest);
  1304. }
  1305.  
  1306. static BYTE *PutRun (BYTE *dest, int nn, int cc)
  1307. {
  1308.   PutByte (-(nn-1));
  1309.  
  1310.   PutByte (cc);
  1311.  
  1312.   return( dest);
  1313. }
  1314.  
  1315. /*----------- packrow --------------------------------------------------*/
  1316.  
  1317. /* Given POINTERS TO POINTERS, packs one row, updating the source and
  1318.  * destination pointers.  RETURNs count of packed bytes. */
  1319.  
  1320. LONG PackRow (BYTE **pSource, BYTE **pDest, LONG rowSize)
  1321. {
  1322. BYTE *source, *dest;
  1323. char c,lastc;
  1324. BOOL mode = DUMP;
  1325. WORD nbuf;       /* number of chars in buffer */
  1326. WORD rstart = 0; /* buffer index current run starts */
  1327.  
  1328.   source = *pSource;
  1329.  
  1330.   dest = *pDest;
  1331.  
  1332.   PackPutSize = 0;
  1333.  
  1334.   PackBuffer [0] = lastc = c = GetByte ();  /* so have valid lastc */
  1335.  
  1336.   nbuf = 1;   rowSize--;    /* since one byte eaten.*/
  1337.  
  1338.   for (;  rowSize;  --rowSize)
  1339.   {
  1340.     PackBuffer [nbuf++] = c = GetByte ();
  1341.  
  1342.     switch (mode)
  1343.     {
  1344.       case DUMP:
  1345.  
  1346.         /* If the buffer is full, write the length byte, then the data */
  1347.         if (nbuf>MaxDat)
  1348.         {
  1349.           OutDump(nbuf-1);
  1350.           PackBuffer[0] = c;
  1351.           nbuf = 1;
  1352.           rstart = 0;
  1353.           break;
  1354.         }
  1355.  
  1356.         if (c == lastc)
  1357.         {
  1358.           if (nbuf-rstart >= MinRun)
  1359.           {
  1360.             if (rstart > 0)
  1361.               OutDump(rstart);
  1362.             mode = RUN;
  1363.           }
  1364.           else
  1365.             if (rstart == 0)
  1366.               mode = RUN; /* no dump in progress, so can't lose by making these 2 a run.*/
  1367.         }
  1368.         else
  1369.           rstart = nbuf-1;      /* first of run */
  1370.         break;
  1371.  
  1372.       case RUN:
  1373.  
  1374.         if ( (c != lastc)|| ( nbuf-rstart > MaxRun))
  1375.         {
  1376.           /* output run */
  1377.           OutRun(nbuf-1-rstart,lastc);
  1378.           PackBuffer[0] = c;
  1379.           nbuf = 1;
  1380.           rstart = 0;
  1381.           mode = DUMP;
  1382.         }
  1383.         break;
  1384.     }
  1385.  
  1386.     lastc = c;
  1387.   }
  1388.  
  1389.   switch (mode)
  1390.   {
  1391.     case DUMP: OutDump (nbuf);
  1392.  
  1393.                break;
  1394.  
  1395.     case RUN:  OutRun (nbuf-rstart,lastc);
  1396.  
  1397.                break;
  1398.   }
  1399.  
  1400.   *pSource = source;
  1401.  
  1402.   *pDest = dest;
  1403.  
  1404.   return (PackPutSize);
  1405. }
  1406.  
  1407. BOOL UnPackRow (BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0)
  1408. {
  1409.   register BYTE *source = *pSource;
  1410.   register BYTE *dest   = *pDest;
  1411.   register WORD n;
  1412.   register WORD srcBytes = srcBytes0;
  1413.   register WORD dstBytes = dstBytes0;
  1414.   BOOL error = TRUE;    /* assume error until we make it through the loop */
  1415.   WORD minus128 = -128;  /* get the compiler to generate a CMP.W */
  1416.   register BYTE c;
  1417.  
  1418.   while( dstBytes > 0 )
  1419.   {
  1420.     if ( (srcBytes -= 1) < 0 )
  1421.     {
  1422.       *pSource = source;
  1423.       *pDest = dest;
  1424.       return(error);
  1425.     }
  1426.     n = UGetByte();
  1427.  
  1428.     if (n >= 0)
  1429.     {
  1430.       n += 1;
  1431.       if ( (srcBytes -= n) < 0 )
  1432.       {
  1433.         *pSource = source;
  1434.         *pDest = dest;
  1435.         return(error);
  1436.       }
  1437.       if ( (dstBytes -= n) < 0 )
  1438.       {
  1439.         *pSource = source;
  1440.         *pDest = dest;
  1441.         return(error);
  1442.       }
  1443.       do
  1444.       {
  1445.         UPutByte(UGetByte());
  1446.       } while (--n > 0);
  1447.     }
  1448.     else
  1449.     if (n != minus128)
  1450.     {
  1451.       n = -n + 1;
  1452.       if ( (srcBytes -= 1) < 0 )
  1453.       {
  1454.         *pSource = source;
  1455.         *pDest = dest;
  1456.         return(error);
  1457.       }
  1458.       if ( (dstBytes -= n) < 0 )
  1459.       {
  1460.         *pSource = source;
  1461.         *pDest = dest;
  1462.         return(error);
  1463.       }
  1464.       c = UGetByte();
  1465.       do
  1466.       {
  1467.         UPutByte(c);
  1468.       } while (--n > 0);
  1469.     }
  1470.   }
  1471.   error = FALSE;    /* success! */
  1472.   *pSource = source;
  1473.   *pDest = dest;
  1474.   return(error);
  1475. }
  1476.  
  1477. /*----------------------------------------------------------------------*/
  1478.  
  1479. /* queryilbm
  1480.  *
  1481.  * Passed an initilized ILBMInfo with a not-in-use IFFHandle,
  1482.  *   and a filename,
  1483.  *   will open an ILBM, fill in ilbm->camg and ilbm->bmhd,
  1484.  *   and close the ILBM.
  1485.  *
  1486.  * This allows you to determine if the ILBM is a size and
  1487.  *   type you want to deal with.
  1488.  *
  1489.  * Returns 0 for success or an IFFERR (libraries/iffparse.h)
  1490.  */
  1491.  
  1492. LONG QueryMandPic (struct ILBMInfo *ilbm,struct MandelChunk **ManChk,UBYTE *filename)
  1493. {
  1494. LONG error;
  1495.  
  1496. BitMapHeader *bmhd;
  1497.  
  1498.   if (! (ilbm->ParseInfo.iff)) return (CLIENT_ERROR);
  1499.  
  1500.   error = openifile (&(ilbm->ParseInfo),filename,IFFF_READ);
  1501.  
  1502.   if (! error)
  1503.   {
  1504.      error = parseifile (&(ilbm->ParseInfo),ID_FORM,ID_ILBM,ilbm->ParseInfo.propchks,ilbm->ParseInfo.collectchks,ilbm->ParseInfo.stopchks);
  1505.  
  1506.      if ((! error) || (error == IFFERR_EOC) || (error == IFFERR_EOF))
  1507.      {
  1508.     if (contextis (ilbm->ParseInfo.iff,ID_ILBM,ID_FORM))
  1509.     {
  1510.        if (*ManChk = (struct MandelChunk *) findpropdata (ilbm->ParseInfo.iff,ID_ILBM,ID_MAND))
  1511.        {
  1512.               if (bmhd = (BitMapHeader *) findpropdata (ilbm->ParseInfo.iff,ID_ILBM,ID_BMHD))
  1513.               {
  1514.                  *(&ilbm->Bmhd) = *bmhd;
  1515.  
  1516.                  ilbm->camg = getcamg (ilbm);
  1517.               }
  1518.  
  1519.               else error = NOFILE;
  1520.        }
  1521.  
  1522.        else error = NOMAND;
  1523.     }
  1524.  
  1525.     else error = NOFILE;
  1526.      }
  1527.  
  1528.      closeifile (&(ilbm->ParseInfo));
  1529.   }
  1530.  
  1531.   return (error);
  1532. }
  1533.  
  1534. /* LoadMandPic
  1535.  *
  1536.  * Passed a not-in-use IFFHandle, an initialized ILBMInfo, and filename,
  1537.  *   will load an ILBM into your already opened ilbm->scr, setting up
  1538.  *   ilbm->Bmhd, ilbm->camg, ilbm->colortable, and ilbm->ncolors
  1539.  *   and loading the colors into the screen's viewport
  1540.  *
  1541.  *   Note that ncolors may be more colors than you can LoadRGB4.
  1542.  *   Use MIN(ilbm->ncolors,vp->ColorMap->Count) for color count if
  1543.  *   you change the colors yourself using 1.3/2.0 functions.
  1544.  *
  1545.  * V39 - unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will do 32-bit
  1546.  *   color load under V39 and higher
  1547.  *
  1548.  * Returns 0 for success or an IFFERR (libraries/iffparse.h)
  1549.  *
  1550.  * NOTE - LoadMandPic () keeps the IFFHandle open so you can copy
  1551.  *   or examine other chunks.  You must call closeifile(iff,ilbm)
  1552.  *   to close the file and deallocate the parsed context
  1553.  *
  1554.  */
  1555.  
  1556. LONG LoadMandPic (struct ILBMInfo *ilbm,UBYTE *filename)
  1557. {
  1558. struct BitMap *TmpBM;
  1559.  
  1560. LONG error;
  1561.  
  1562.   if (! (ilbm->ParseInfo.iff)) return (CLIENT_ERROR);
  1563.  
  1564.   if (! ilbm->scr) return (CLIENT_ERROR);
  1565.  
  1566.   if (! (ilbm->vp)) ilbm->vp = &ilbm->scr->ViewPort;
  1567.  
  1568.   error = openifile (&(ilbm->ParseInfo),filename,IFFF_READ);
  1569.  
  1570.   if (! error)
  1571.   {
  1572.      error = parseifile (&(ilbm->ParseInfo),ID_FORM,ID_ILBM,ilbm->ParseInfo.propchks,ilbm->ParseInfo.collectchks,ilbm->ParseInfo.stopchks);
  1573.  
  1574.      if ((! error) || (error == IFFERR_EOC) || (error == IFFERR_EOF))
  1575.      {
  1576.         if (contextis (ilbm->ParseInfo.iff,ID_ILBM,ID_FORM))
  1577.         {
  1578.            if (GetBitMapAttr (ilbm->wrp->BitMap,BMA_FLAGS) & BMF_STANDARD)
  1579.            {
  1580.               if (! (error = loadbody (ilbm->ParseInfo.iff,ilbm->wrp->BitMap,&ilbm->Bmhd)));
  1581.            }
  1582.  
  1583.            else
  1584.            {
  1585.               if (TmpBM = AllocBitMap ((ULONG) ilbm->win->Width,(ULONG) ilbm->win->Height,(ULONG) ilbm->wrp->BitMap->Depth,BMF_INTERLEAVED | BMF_CLEAR | BMF_MINPLANES,NULL))
  1586.               {
  1587.                  if (! (error = loadbody (ilbm->ParseInfo.iff,TmpBM,&ilbm->Bmhd)))
  1588.  
  1589.                     BltBitMapRastPort (TmpBM,(LONG) ilbm->win->LeftEdge,(LONG) ilbm->win->TopEdge,ilbm->wrp,(LONG) ilbm->win->LeftEdge,(LONG) ilbm->win->TopEdge,(LONG) ilbm->win->Width,(LONG) ilbm->win->Height,0xC0);
  1590.  
  1591.                  FreeBitMap (TmpBM);
  1592.               }
  1593.            }
  1594.  
  1595.            if (! (getcolors (ilbm)))
  1596.            {
  1597.               setcolors (ilbm,ilbm->vp);
  1598.  
  1599.               freecolors (ilbm);
  1600.            }
  1601.         }
  1602.  
  1603.         else error = NOFILE;
  1604.      }
  1605.  
  1606.      closeifile (&(ilbm->ParseInfo));
  1607.   }
  1608.  
  1609.   return (error);
  1610. }
  1611.  
  1612. LONG SaveMandPic (struct ILBMInfo *ilbm,struct Chunk *chunklist1,struct Chunk *chunklist2,UBYTE *filename)
  1613. {
  1614. struct BitMap *TmpBM;
  1615.  
  1616. Color32 *colortable32;
  1617.  
  1618. UWORD count;
  1619.  
  1620. ULONG modeid;
  1621.  
  1622. LONG error = IFFERR_NOMEM;
  1623.  
  1624.   modeid = GetVPModeID (ilbm->vp);
  1625.  
  1626.   count = ilbm->vp->ColorMap->Count;
  1627.  
  1628.   if (colortable32 = (Color32 *) AllocVec ((ULONG) (sizeof (Color32) * count),MEMF_CLEAR))
  1629.   {
  1630.      if (GetBitMapAttr (ilbm->wrp->BitMap,BMA_FLAGS) & BMF_STANDARD)
  1631.      {
  1632.         GetRGB32 (ilbm->vp->ColorMap,0L,(ULONG) count,(ULONG *) colortable32);
  1633.  
  1634.         error = saveilbm (ilbm,ilbm->wrp->BitMap,modeid,ilbm->win->Width,ilbm->win->Height,ilbm->win->Width,ilbm->win->Height,colortable32,count,32,mskNone,0,chunklist1,chunklist2,filename);
  1635.      }
  1636.  
  1637.      else
  1638.      {
  1639.         if (TmpBM = AllocBitMap ((ULONG) ilbm->win->Width,(ULONG) ilbm->win->Height,(ULONG) ilbm->wrp->BitMap->Depth,BMF_INTERLEAVED | BMF_CLEAR | BMF_MINPLANES,NULL))
  1640.         {
  1641.            GetRGB32 (ilbm->vp->ColorMap,0L,(ULONG) count,(ULONG *) colortable32);
  1642.  
  1643.            BltBitMap (ilbm->wrp->BitMap,(LONG) ilbm->win->LeftEdge,(LONG) ilbm->win->TopEdge,TmpBM,(LONG) ilbm->win->LeftEdge,(LONG) ilbm->win->TopEdge,(LONG) ilbm->win->Width,(LONG) ilbm->win->Height,0xC0,0xFF,NULL);
  1644.  
  1645.            error = saveilbm (ilbm,TmpBM,modeid,ilbm->win->Width,ilbm->win->Height,ilbm->win->Width,ilbm->win->Height,colortable32,count,32,mskNone,0,chunklist1,chunklist2,filename);
  1646.  
  1647.            FreeBitMap (TmpBM);
  1648.         }
  1649.      }
  1650.  
  1651.      FreeVec (colortable32);
  1652.   }
  1653.  
  1654.   return (error);
  1655. }
  1656.  
  1657. LONG LoadPalette (struct ILBMInfo *ilbm,UBYTE *filename)
  1658. {
  1659. LONG error;
  1660.  
  1661.   error = openifile (&(ilbm->ParseInfo),filename,IFFF_READ);
  1662.  
  1663.   if (! error)
  1664.   {
  1665.      error = parseifile (&(ilbm->ParseInfo),ID_FORM,ID_ILBM,ilbm->ParseInfo.propchks,ilbm->ParseInfo.collectchks,ilbm->ParseInfo.stopchks);
  1666.  
  1667.      if ((! error) || (error == IFFERR_EOC) || (error == IFFERR_EOF))
  1668.      {
  1669.         if (! (error = getcolors (ilbm)))
  1670.         {
  1671.            setcolors (ilbm,ilbm->vp);
  1672.  
  1673.            freecolors (ilbm);
  1674.         }
  1675.      }
  1676.  
  1677.      closeifile (&(ilbm->ParseInfo));
  1678.   }
  1679.  
  1680.   return (error);
  1681. }
  1682.  
  1683. LONG SavePalette (struct ILBMInfo *ilbm,struct Chunk *chunklist,UBYTE *filename)
  1684. {
  1685. struct IFFHandle *iff;
  1686.  
  1687. struct Chunk *chunk;
  1688.  
  1689. Color32 *colortable32;
  1690.  
  1691. UWORD ncolors;
  1692.  
  1693. LONG size,error;
  1694.  
  1695. ULONG chunkID;
  1696.  
  1697.   iff = ilbm->ParseInfo.iff;
  1698.  
  1699.   ncolors = ilbm->vp->ColorMap->Count;
  1700.  
  1701.   error = openifile (&(ilbm->ParseInfo),filename,IFFF_WRITE);
  1702.  
  1703.   if (! error)
  1704.   {
  1705.     error = PushChunk (iff,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN);
  1706.  
  1707.     if (colortable32 = (Color32 *) AllocVec ((ULONG) (sizeof (Color32) * ncolors),MEMF_CLEAR))
  1708.     {
  1709.        GetRGB32 (ilbm->vp->ColorMap,0L,(ULONG) ncolors,(ULONG *) colortable32);
  1710.  
  1711.        CkErr (putcmap (iff,colortable32,ncolors,32));
  1712.  
  1713.        FreeVec (colortable32);
  1714.     }
  1715.  
  1716.     for (chunk = chunklist; chunk; chunk = chunk->ch_Next)
  1717.     {
  1718.       chunkID = chunk->ch_ID;
  1719.  
  1720.       if ((chunkID != ID_BMHD) && (chunkID != ID_CMAP) && (chunkID != ID_CAMG))
  1721.       {
  1722.         size = chunk->ch_Size == IFFSIZE_UNKNOWN ? strlen (chunk->ch_Data) : chunk->ch_Size;
  1723.  
  1724.         CkErr (PutCk (iff,chunkID,size,chunk->ch_Data));
  1725.       }
  1726.     }
  1727.  
  1728.     CkErr (PopChunk (iff)); /* close out the FORM */
  1729.  
  1730.     closeifile (&(ilbm->ParseInfo));    /* and the file */
  1731.   }
  1732.  
  1733.   return (error);
  1734. }
  1735.